[XEN] Implement XENMEM_set_memory_map, which specifies memory map to
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 8 Dec 2006 11:30:30 +0000 (11:30 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 8 Dec 2006 11:30:30 +0000 (11:30 +0000)
be returned by XENMEM_memory_map. Hook this into the domain builder.

Based on a patch by Glauber de Oliveira Costa <gcosta@redhat.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
tools/libxc/xc_domain.c
tools/libxc/xenctrl.h
tools/python/xen/lowlevel/xc/xc.c
tools/python/xen/xend/image.py
xen/arch/x86/mm.c
xen/include/asm-x86/domain.h
xen/include/public/memory.h

index b63e172a2201ac3d95eed2cac057867d6e42d85e..82aef99ccc16d2c449cf7d89a5eeea42597c3ce5 100644 (file)
@@ -316,6 +316,52 @@ int xc_domain_setmaxmem(int xc_handle,
     return do_domctl(xc_handle, &domctl);
 }
 
+#if defined(__i386__) || defined(__x86_64__)
+#include <xen/hvm/e820.h>
+int xc_domain_set_memmap_limit(int xc_handle,
+                               uint32_t domid,
+                               unsigned long map_limitkb)
+{
+    int rc;
+
+    struct xen_foreign_memory_map fmap = {
+        .domid = domid,
+        .map = { .nr_entries = 1 }
+    };
+
+    struct e820entry e820 = {
+        .addr = 0,
+        .size = (uint64_t)map_limitkb << 10,
+        .type = E820_RAM
+    };
+
+    set_xen_guest_handle(fmap.map.buffer, &e820);
+
+    if ( lock_pages(&fmap, sizeof(fmap)) || lock_pages(&e820, sizeof(e820)) )
+    {
+        PERROR("Could not lock memory for Xen hypercall");
+        rc = -1;
+        goto out;
+    }
+
+    rc = xc_memory_op(xc_handle, XENMEM_set_memory_map, &fmap);
+
+ out:
+    unlock_pages(&fmap, sizeof(fmap));
+    unlock_pages(&e820, sizeof(e820));
+    return rc;
+}
+#else
+int xc_domain_set_memmap_limit(int xc_handle,
+                               uint32_t domid,
+                               unsigned long map_limitkb)
+{
+    PERROR("Function not implemented");
+    errno = ENOSYS;
+    return -1;
+}
+#endif
+
 int xc_domain_set_time_offset(int xc_handle,
                               uint32_t domid,
                               int32_t time_offset_seconds)
index d0a9f5db9754e8a4f0cb3c4e4c6f20b757fb5495..00fa713562d7406c71a156fa977942978277bb1f 100644 (file)
@@ -419,6 +419,10 @@ int xc_domain_setmaxmem(int xc_handle,
                         uint32_t domid,
                         unsigned int max_memkb);
 
+int xc_domain_set_memmap_limit(int xc_handle,
+                               uint32_t domid,
+                               unsigned long map_limitkb);
+
 int xc_domain_set_time_offset(int xc_handle,
                               uint32_t domid,
                               int32_t time_offset_seconds);
index e74a882fe073f367f4dfe37a15dd511d467c1fac..0d68d89f28863e4fde8a89f14ba954167cf8fb12 100644 (file)
@@ -758,6 +758,21 @@ static PyObject *pyxc_domain_setmaxmem(XcObject *self, PyObject *args)
     return zero;
 }
 
+static PyObject *pyxc_domain_set_memmap_limit(XcObject *self, PyObject *args)
+{
+    uint32_t dom;
+    unsigned int maplimit_kb;
+
+    if ( !PyArg_ParseTuple(args, "ii", &dom, &maplimit_kb) )
+        return NULL;
+
+    if ( xc_domain_set_memmap_limit(self->xc_handle, dom, maplimit_kb) != 0 )
+        return pyxc_error_to_exception();
+    
+    Py_INCREF(zero);
+    return zero;
+}
+
 static PyObject *pyxc_domain_memory_increase_reservation(XcObject *self,
                                                          PyObject *args,
                                                          PyObject *kwds)
@@ -1141,6 +1156,14 @@ static PyMethodDef pyxc_methods[] = {
       " maxmem_kb [int]: .\n"
       "Returns: [int] 0 on success; -1 on error.\n" },
 
+    { "domain_set_memmap_limit", 
+      (PyCFunction)pyxc_domain_set_memmap_limit, 
+      METH_VARARGS, "\n"
+      "Set a domain's physical memory mappping limit\n"
+      " dom [int]: Identifier of domain.\n"
+      " map_limitkb [int]: .\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
     { "domain_memory_increase_reservation", 
       (PyCFunction)pyxc_domain_memory_increase_reservation, 
       METH_VARARGS | METH_KEYWORDS, "\n"
index 29eea9dc55ae2182f763a3f2e73af69738aabab9..2ccc8615e9cc06f01dab6809bd184d3446ae5f87 100644 (file)
@@ -548,6 +548,14 @@ class X86_HVM_ImageHandler(HVMImageHandler):
         return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)),
                    shadow_mem_kb)
 
+class X86_Linux_ImageHandler(LinuxImageHandler):
+
+    def buildDomain(self):
+        # set physical mapping limit
+        # add an 8MB slack to balance backend allocations.
+        mem_kb = self.getRequiredInitialReservation() + (8 * 1024)
+        xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb)
+        return LinuxImageHandler.buildDomain(self)
 
 _handlers = {
     "powerpc": {
@@ -558,7 +566,7 @@ _handlers = {
         "hvm": IA64_HVM_ImageHandler,
     },
     "x86": {
-        "linux": LinuxImageHandler,
+        "linux": X86_Linux_ImageHandler,
         "hvm": X86_HVM_ImageHandler,
     },
 }
index 9a965f982b6ce63e6f12730f05260b19e685c8a9..4fd69400f32b99cd33fb78d188e493641ea1e8a4 100644 (file)
@@ -2978,9 +2978,54 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
         break;
     }
 
+    case XENMEM_set_memory_map:
+    {
+        struct xen_foreign_memory_map fmap;
+        struct domain *d;
+        int rc;
+
+        if ( copy_from_guest(&fmap, arg, 1) )
+            return -EFAULT;
+
+        if ( fmap.map.nr_entries > ARRAY_SIZE(d->arch.e820) )
+            return -EINVAL;
+
+        if ( fmap.domid == DOMID_SELF )
+        {
+            d = current->domain;
+            get_knownalive_domain(d);
+        }
+        else if ( !IS_PRIV(current->domain) )
+            return -EPERM;
+        else if ( (d = find_domain_by_id(fmap.domid)) == NULL )
+            return -ESRCH;
+
+        rc = copy_from_guest(&d->arch.e820[0], fmap.map.buffer,
+                             fmap.map.nr_entries) ? -EFAULT : 0;
+        d->arch.nr_e820 = fmap.map.nr_entries;
+
+        put_domain(d);
+        return rc;
+    }
+
     case XENMEM_memory_map:
     {
-        return -ENOSYS;
+        struct xen_memory_map map;
+        struct domain *d = current->domain;
+
+        /* Backwards compatibility. */
+        if ( d->arch.nr_e820 == 0 )
+            return -ENOSYS;
+
+        if ( copy_from_guest(&map, arg, 1) )
+            return -EFAULT;
+
+        map.nr_entries = min(map.nr_entries, d->arch.nr_e820);
+        if ( copy_to_guest(map.buffer, &d->arch.e820[0], map.nr_entries) ||
+             copy_to_guest(arg, &map, 1) )
+            return -EFAULT;
+
+        return 0;
     }
 
     case XENMEM_machine_memory_map:
index 20793910baebe2331cca3885d92b57c772fb005d..efda6dd263cee6f8ad8a128b15d2cec43f1aded4 100644 (file)
@@ -5,6 +5,7 @@
 #include <xen/mm.h>
 #include <asm/hvm/vcpu.h>
 #include <asm/hvm/domain.h>
+#include <asm/e820.h>
 
 struct trap_bounce {
     unsigned long  error_code;
@@ -100,11 +101,7 @@ struct arch_domain
     /* I/O-port admin-specified access capabilities. */
     struct rangeset *ioport_caps;
 
-    /* HVM stuff */
-    struct hvm_domain   hvm_domain;
-
-    /* Shadow-translated guest: Pseudophys base address of reserved area. */
-    unsigned long first_reserved_pfn;
+    struct hvm_domain hvm_domain;
 
     struct shadow_domain shadow;
 
@@ -113,6 +110,9 @@ struct arch_domain
     /* Highest guest frame that's ever been mapped in the p2m */
     unsigned long max_mapped_pfn;
 
+    /* Pseudophysical e820 map (XENMEM_memory_map).  */
+    struct e820entry e820[3];
+    unsigned int nr_e820;
 } __cacheline_aligned;
 
 #ifdef CONFIG_X86_PAE
index e28ed1262051a62c09e3c54888f56f63c2586cd3..acbc89b7e7e29c86ba6f9b3017e0c2c6c34c33db 100644 (file)
@@ -222,7 +222,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t);
 
 /*
  * Returns the pseudo-physical memory map as it was when the domain
- * was started.
+ * was started (specified by XENMEM_set_memory_map).
+ * arg == addr of xen_memory_map_t.
  */
 #define XENMEM_memory_map           9
 struct xen_memory_map {
@@ -245,9 +246,23 @@ DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t);
 /*
  * Returns the real physical memory map. Passes the same structure as
  * XENMEM_memory_map.
+ * arg == addr of xen_memory_map_t.
  */
 #define XENMEM_machine_memory_map      10
 
+/*
+ * Set the pseudo-physical memory map of a domain, as returned by
+ * XENMEM_memory_map.
+ * arg == addr of xen_foreign_memory_map_t.
+ */
+#define XENMEM_set_memory_map       13
+struct xen_foreign_memory_map {
+    domid_t domid;
+    struct xen_memory_map map;
+};
+typedef struct xen_foreign_memory_map xen_foreign_memory_map_t;
+DEFINE_XEN_GUEST_HANDLE(xen_foreign_memory_map_t);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
 /*